import thx.sys.Lib;
import uform.model.core.Schema;
import uform.model.value.Value;
import uform.ui.build.html5.Html5Builder;
import uform.ui.comp.Trigger;
import uform.ui.comp.Form;
import uform.model.generator.Generator;
import thx.html.Html;
import thx.html.HtmlVersion;
using Types;
using StringTools;
import uform.ui.comp.Group;
import uform.ui.comp.Control;
import uform.ui.comp.FormMode;
import uform.ui.comp.TriggerKind;

class DemoSchemaGenerator
{
	public static function main()
	{
		var form = new Form("book", HttpSubmit(null, Get));
		form.model.schema = Generator.generate(Book);
		form.action = new Trigger("submit", "submit", TriggerKind.Submit, function() {
			trace("submit");
		});
		
		var values = thx.sys.Web.getParamsString().split("&");

		var actions = [];
		for (s in values)
		{
			var pair = s.split("=");
			var path = StringTools.urlDecode(pair[0]);
			var isaction = path.startsWith("!");
			if (isaction)
				path = path.substr(1);
			if (form.name != "" && !path.startsWith(form.name + "."))
				continue;
			if (isaction)
			{
				actions.push(path);
				continue;
			}
			var value = StringTools.urlDecode(pair[1]);
			switch(form.model.validateStringAt(path, value))
			{
				case Ok:
					form.model.setString(path, value);
				case Failure(e):
					form.componentByPath(path).ifIs(Control, function(input) {
						var arr = input.errors.get();
						if (null == arr)
							arr = e;
						else
							arr = arr.concat(e);
						input.errors.set(arr);
					});
			}
		}
		
		var submited = false;
		for (path in actions)
		{
			var component = form.componentByPath(path);
			if (null == component)
				continue;
			component.ifIs(Trigger, function(t) {
				submited = true;
				t.trigger();
			});
		}
		if (!submited)
			form.model.data = new Book("Pro haXe and Neko", "my book", [new Author("Franco", "Ponticelli"), new Author("Lee", "Sylvester", "McColl")], false, ["haxe", "neko"]);

		var doc = Html.createDocument(Html5);
		
		Html.getTitle(doc).addChild(Xml.createPCData("uform server demo"));	
		Html.getBody(doc).addChild(Html5Builder.buildXml(form));
		
		var formatter = Html.getFormatter(Html5);
		formatter.indent = "  ";
		Lib.print(formatter.format(doc));
	}
}

class Book
{
	public function new(?title : String, ?description : String, ?authors : Array<Author>, ?toread : Bool, ?tags : Array<String>)
	{
		this.title = title;
		this.description = description;
		this.authors = null == authors ? [] : authors;
		this.toRead = toread;
		this.tags = tags;
	}
	
	@field({min:5, max:100, description:"the book title"})
	public var title : String;
	@field({ kind:"multiline", description:"a small abstract" } )
	public var description : String;
	
	@field({ kind:"file" })
	public var file : Null<String>;
	
	public var authors : Array<Author>;
	@field({label:"still to read?",value:true})
	public var toRead : Bool;
	@field({rangemin:1,rangemax:10,min:1,max:20,description:"keywords associated to topics in the book"})
	public var tags : Array<String>;

	@field({options:["good","bad","decent"],value:"good"})
	public var opinion : Null<String>;
	
	public function toString() return title
}

class Author
{
	public function new(?firstname : String, ?lastname : String, ?middlename : String, ?birthyear : Int, ?male : Bool)
	{
		this.firstName = firstname;
		this.lastName = lastname;
		this.middleName = middlename;
		this.birthYear = birthyear;
		this.male = male;
	}

	@field({min:1, max:50})
	public var firstName : String;
	@field({min:1, max:50})
	public var lastName : String;
	@field({min:1, max:20})
	public var middleName : Null<String>;
	@field({min:1900, max:2010, value:1980})
	public var birthYear : Null<Int>;
	@field({value:true})
	public var male : Null<Bool>;
	@field({kind:"email"})
	public var email : Null<String>;
	@field({value:3,min:1,max:5})
	public var stars : Null<Int>;

	public function toString() return lastName + ", " + firstName
}